package com.michaelbulava.TFS.ui.controls.workspaces;

import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.ui.AddEditRemovePanel;
import com.michaelbulava.TFS.Messages;
import com.michaelbulava.TFS.tasks.BackgroundableTask;
import com.michaelbulava.TFS.tasks.workspaces.QueryLocalWorkspacesTask;
import com.michaelbulava.TFS.ui.controls.workspaces.WorkspaceData;
import com.michaelbulava.TFS.ui.dialogs.workspaces.WorkspaceEditDialog;
import com.microsoft.tfs.core.TFSTeamProjectCollection;
import com.microsoft.tfs.core.clients.versioncontrol.VersionControlClient;
import com.microsoft.tfs.core.clients.versioncontrol.Workstation;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;
import com.microsoft.tfs.jni.helpers.LocalHost;
import com.microsoft.tfs.util.xml.XMLException;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.io.FileNotFoundException;
import java.text.MessageFormat;
import java.util.ArrayList;

import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Created by mbulava on 6/25/2015.
 */
public class WorkspacesControl extends AddEditRemovePanel<Workspace> {

    
    private static  final String[] COLUMNS = new String[] {
            Messages.getString("WorkspacesControl.Model.Column1"),
            Messages.getString("WorkspacesControl.Model.Column2"),
            Messages.getString("WorkspacesControl.Model.Column3"),
            Messages.getString("WorkspacesControl.Model.Column4")
    };

    public interface SelectedWorkspaceChangeListener{
        void onSelectionChanged(Workspace newSelection);
    }

    private List<SelectedWorkspaceChangeListener> listeners = new ArrayList<SelectedWorkspaceChangeListener>();
    private Workspace mSelectedWorkspace = null;

    private TFSTeamProjectCollection collection;

    public WorkspacesControl() {
        super(new WorkspacesModel(),
                new ArrayList<Workspace>(),
                Messages.getString("WorkspacesControl.Label.Text"));
        getTable().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        getTable().setRowSelectionAllowed(true);
        getTable().setColumnSelectionAllowed(false);

        addSelectedWorkspaceChangeListener(new SelectedWorkspaceChangeListener() {
            @Override
            public void onSelectionChanged(Workspace newSelection) {
                mSelectedWorkspace = newSelection;
            }
        });
        ListSelectionModel cellSelectionModel = getTable().getSelectionModel();
        cellSelectionModel.addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                ListSelectionModel lsm = (ListSelectionModel)e.getSource();
                Workspace selectedWorkspace = null;
                if (!lsm.isSelectionEmpty()){
                    int value = getTable().getSelectedRow();
                    selectedWorkspace = getData().get(value);
                }
                if (listeners.size() > 0){
                    for(SelectedWorkspaceChangeListener l : listeners){
                        l.onSelectionChanged(selectedWorkspace);
                    }
                }
            }
        });
        super.getTable().setShowColumns(true);
    }


    public final void addSelectedWorkspaceChangeListener(SelectedWorkspaceChangeListener value){
        this.listeners.add(value);
    }

    public final void removeSelectedWorkspaceChangeListener(SelectedWorkspaceChangeListener value){
        this.listeners.remove(value);
    }

    public final Workspace getSelectedWorkspace(){
        return this.mSelectedWorkspace;
    }

    public final void refresh(TFSTeamProjectCollection collection){
        //Clear the current list
        setData(new ArrayList<Workspace>());
        this.collection = collection;
        if (collection  != null){
            QueryLocalWorkspacesTask task = new QueryLocalWorkspacesTask(collection);
            ProgressManager.getInstance().run(task);

            setData(task.getWorkspaces());
        }
    }

    @Nullable
    @Override
    protected Workspace addItem() {
        String defaultWorkspaceName = computeNewWorkspaceName(LocalHost.getShortName(), getData().toArray(new Workspace[0]));
        WorkspaceData workspaceData = new WorkspaceData(this.collection, defaultWorkspaceName);
        WorkspaceEditDialog dialog = new WorkspaceEditDialog(this, workspaceData ,collection);
        if (dialog.showAndGet())
            return dialog.getWorkspace();

        return null;
    }

    @Override
    protected boolean removeItem(Workspace workspace) {
        boolean value = (Messages.showYesNoDialog(this, MessageFormat.format(
                Messages.getString("WorkspacesControl.ConfirmDeleteMessageFormat"),
                        new Object[] { workspace.getName() }),
                Messages.getString("WorkspacesControl.ConfirmDeleteTitle")) == Messages.YES);
        if (value){
            workspace.getClient().deleteWorkspace(workspace);
        }
        return value;
    }

    @Nullable
    @Override
    protected Workspace editItem(Workspace workspace) {
        WorkspaceEditDialog dialog = new WorkspaceEditDialog(this, workspace);
        if (dialog.showAndGet())
            return dialog.getWorkspace();

        return null;
    }


    private static class WorkspacesModel extends TableModel<Workspace> {

        @Override
        public int getColumnCount() {
            return COLUMNS.length;
        }

        @Nullable
        @Override
        public String getColumnName(int i) {
            return COLUMNS[i];
        }

        @Override
        public Object getField(Workspace workspace, int i) {
            switch(i){
                case 0:
                    return workspace.getName();
                case 1:
                    return workspace.getComputer();
                case 2:
                    return workspace.getOwnerName();
                case 3:
                    return workspace.getComment();
                default:
                    return null;
            }
        }

    }
/*
    private static class QueryLocalWorkspacesTask extends BackgroundableTask{
        private final VersionControlClient vcClient;
        private List<Workspace> workspaces;

        protected QueryLocalWorkspacesTask(TFSTeamProjectCollection collection) {
            super(null, "Querying local workspaces...", false);
            this.vcClient = collection.getVersionControlClient();
        }

        @Override
        protected boolean runInBackground() {
            return false;
        }

        @Override
        public void run(ProgressIndicator progressIndicator) {
            String messageFormat = "Querying workspaces on {0}";
            String message = MessageFormat.format(messageFormat, new Object[]{this.vcClient.getConnection().getName()});
            progressIndicator.setText(message);

            AtomicReference<Workspace[]> workspacesHolder = new AtomicReference<Workspace[]>();

            try{
                Workstation.getCurrent(this.vcClient.getConnection().getPersistenceStoreProvider())
                        .updateWorkspaceInfoCache(this.vcClient, this.vcClient.getConnection()
                                .getAuthorizedTFSUser().toString(), workspacesHolder);
            }catch(XMLException e){
                if (!(e.getCause() instanceof FileNotFoundException))
                    throw e;
            }
            //Using Arrays.asList over the returned array casts the value to an Arraylist hosted in java.util.Arrays,
            //which doesn't allow for removing items.
            Workspace[] found = workspacesHolder.get();
            if (found != null && found.length > 0){
                this.workspaces = new ArrayList<Workspace>();
                for(int i = 0; i < found.length; i++){
                    this.workspaces.add(found[i]);
                }
            } else {
                this.workspaces = new ArrayList<Workspace>();
            }
        }

        public List<Workspace> getWorkspaces()
        {
            return this.workspaces;
        }
    }*/

    private static String computeNewWorkspaceName(String baseName, Workspace[] existingWorkspaces) {
        String candidateName = baseName;
        boolean keepGoing = true;
        int ix = 0;
        while (keepGoing) {
            boolean matched = false;
            for (int i = 0; (!matched) && (i < existingWorkspaces.length); i++) {
                matched = existingWorkspaces[i].getName().equalsIgnoreCase(candidateName);
                if (matched) {
                    break;
                }
            }
            if (!matched)
                keepGoing = false;
            else {
                String messageFormat = Messages.getString("WorkspacesControl.DefaultNewWorkspaceNameFormat");
                candidateName = MessageFormat.format(messageFormat, new Object[] { baseName, Integer.toString(++ix) });
            }
        }
        return candidateName;
    }
}
